<?php

namespace App\Service;

/**
 * 通用的树型类，可以生成任何树型结构
 */
class Tree
{

    /**
     * 生成树型结构所需修饰符号，可以换成图片
     * @var array
     */
    public $icon = array('│', '├', '└');

    /**
     * @access private
     */
    public $ret = '';

    /**
     * 构造函数，初始化类
     * @param array 2维数组，例如：
     * array(
     *      1 => array('id'=>'1','parentid'=>0,'name'=>'一级栏目一'),
     *      2 => array('id'=>'2','parentid'=>0,'name'=>'一级栏目二'),
     *      3 => array('id'=>'3','parentid'=>1,'name'=>'二级栏目一'),
     *      4 => array('id'=>'4','parentid'=>1,'name'=>'二级栏目二'),
     *      5 => array('id'=>'5','parentid'=>2,'name'=>'二级栏目三'),
     *      6 => array('id'=>'6','parentid'=>3,'name'=>'三级栏目一'),
     *      7 => array('id'=>'7','parentid'=>3,'name'=>'三级栏目二')
     *      )
     */
    public function __construct()
    {
    }

    ## 树状操作  用驼峰式命令方法
    ## 以下效率高些

    /**
     * 将数据集格式化成树形结构
     * @param array $data 原始数据
     * @param int $myid 自己的id
     * @param int $limitLevel 限制返回几层，0为不限制
     * @param int $currentLevel 当前层数（其他地方调用的时候，几乎不用，一般仅供自己调用）
     * @return array
     */
    public function toTree($data = [], $myid = 0, $limitLevel = 0, $currentLevel = 0)
    {
        $trees = [];
        $data  = array_values($data);

        foreach($data as $k => $v){
            if($v['pid'] == $myid){
                if($limitLevel > 0 && $limitLevel == $currentLevel){
                    return $trees;
                }

                unset($data[$k]);

                $children = $this->toTree($data, $v['id'], $limitLevel, ($currentLevel + 1));
                if(!empty($children)){
                    $v['child'] = $children;
                }else{
                    // 根据前端要求，只有第一个的子级才有数据
                    if($currentLevel===0){
                        $v['child'] = [];
                    }
                }
                $trees[] = $v;
            }
        }

        return $trees;
    }

    /**
     * 将数据集格式化成树形结构
     * 返回数据，不包含自己这一条数据
     * @param array $data 原始数据
     * @param int $myid 自己的id
     * @param int $limitLevel 限制返回几层，0为不限制
     * @param int $currentLevel 当前层数（其他地方调用的时候，几乎不用，一般仅供自己调用）
     * @return array
     */
    public function toList($data = [], $myid = 0, $limitLevel = 0, $currentLevel = 0)
    {
        $trees = [];
        $data  = array_values($data);
        foreach($data as $k => $v){
            if($v['pid'] == $myid){
                if($limitLevel > 0 && $limitLevel == $currentLevel){
                    return $trees;
                }

                $v['level'] = $currentLevel;
                unset($data[$k]);

                $trees[]  = $v;
                $children = $this->toList($data, $v['id'], $limitLevel, ($currentLevel + 1));
                if(!empty($children)){
                    $trees = array_merge($trees, $children);
                }
            }
        }

        return $trees;
    }

    // 获取所有的子级 【暂无使用】
    public function getAllChild($data = [], $myid = 0, $limitLevel = 0, $currentLevel = 0)
    {
        return $this->toTree($data, $myid, $limitLevel, $currentLevel);
    }

    // 得到一级子级数组的id 【暂无使用】
    public function getChildId($data = [], $myid = 0)
    {
        $newarr = array();
        if(is_array($data)){
            foreach($data as $id => $item){
                if($item['pid'] == $myid){
                    $newarr[] = $item['id'];
                }
            }
        }

        return $newarr;
    }

    //递归获取所有的子分类的ID 不包含自己的子级分类
    public function getAllChildId($data = [], $id = 0)
    {
        $arr = array();
        if(is_array($data)){
            foreach($data as $k => $v){
                if($v['pid'] == $id){
                    $arr[] = $v['id'];
                    unset($data[$k]);
                    $arr = array_merge($arr, $this->getAllChildId($data, $v['id']));
                };
            };
        }

        return $arr;
    }


    /**
     * 得到所有的父级信息
     * $myid 自己的id
     * $data  数组信息
     * 返回数组信息是有顶级到末级（包含自己）
     ****/
    public function getParent($myid, $data = [])
    {
        $return = [];
        foreach($data as $item){
            // 查询自己 判断自己的父级是否存在
            if($item['id'] == $myid){
                $pid = $item['pid'];
                if($pid > 0){
                    // 查询父级 获取父级
                    foreach($data as $it){
                        if($it['id'] == $pid){
                            $return = $it;
                            break;
                        }
                    }
                    break;
                }
                break;
            }
        }

        return $return;
    }


    /**
     * 得到所有的父级信息
     * $myid 自己的id
     * $arr  数组信息
     * 返回数组信息是有顶级到末级（包含自己）
     ****/
    function getAllParent($myid, $data = [])
    {
        $tree = array();
        foreach($data as $item){
            if($item['id'] == $myid){
                if($item['pid'] > 0){
                    $tree = array_merge($tree, $this->getAllParent($item['pid'], $data));
                }
                $tree[] = $item;
                break;
            }
        }

        return $tree;
    }

    /**
     * 得到最顶层的父级信息
     * $myid 自己的id
     * $arr  数组信息
     * 返回数组信息是有顶级到末级（包含自己）
     ****/
    function getTopParent($myid, $data = [])
    {
        $result = array();
        foreach($data as $item){
            if($item['id'] != $myid){
                continue;
            }
            if($item['pid'] > 0){
                $result = $this->getTopParent($item['pid'], $data);
            } else{
                $result = $item;
            }
        }

        return $result;
    }

    /**
     * 得到所有父级的指定字段 【暂无使用】
     * $myid 自己的id
     * $arr  数组信息
     * $field  指定字段
     * $concat  链接字符
     * 返回数组信息是有顶级到末级
     ****/
    function getAllParentField($myid, $data = [], $field = 'id', $concat = ',')
    {
        $parent = $this->getAllParent($myid, $data);
        $return = $comm = '';
        foreach($parent as $kk => $vv){
            $return .= $comm.$vv[$field];
            $comm   = $concat;
        }

        return $return;
    }

}
